package util

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/davecgh/go-spew/spew"
	"github.com/redis/go-redis/v9"
	"log/slog"
	"rule/ast"
	"rule/cache"
	"rule/data"
	"rule/internal/bytesconv"
	"rule/model"
	"strconv"
)

var (
	redisMqMsg  chan string = make(chan string, 4)
	redisMqData             = make(chan *data.MyDataReport, 20)
)

// (map[string]interface {}) (len=8) {
// (string) (len=6) "ruleId": (string) (len=2) "80",
// (string) (len=6) "status": (string) (len=1) "1",
// (string) (len=14) "ruleExpression": (string) (len=21) "(${_1000520359} > 10)",
// (string) (len=14) "expressionList": (string) (len=19) "${_1000520359} > 10",
// (string) (len=8) "ptIdList": (string) (len=14) "_1000520359@10",
// (string) (len=11) "linkageList": (string) (len=85) "[{\"ptId\":\"1000520359\",\"setpointOperator\":2,\"setpointValue\":2.0,\"triggerInterval\":30}]",
// (string) (len=9) "alarmTime": (string) (len=2) "12",
// (string) (len=2) "id": (string) (len=1) "0"
//}

const (
	REDIS_KEY_RULE_ENGINE string = "rule_engine"
	rule_deleted          string = "rule_deleted"
	rule_changed          string = "rule_changed"
	ctrl_ptid_prefix      string = "ctrl:ptid:"
)

// 仅仅在程序启动的时候, 对现有旧数据的进行加载
func ReadRuleFromRedis() {
	//
	strSliceCmd := cache.Rdb0.ZRange(ctx, REDIS_KEY_RULE_ENGINE, 0, 10000)
	if strSliceCmd == nil {
		slog.Error("ZRange data", "error", strSliceCmd.Err().Error())
		return
	}
	strArray, err := strSliceCmd.Result()
	if err != nil {
		slog.Error("ZRange data", "error", err.Error())
		return
	}
	//

	for _, s := range strArray {
		slog.Warn("rule_engine redis data", "rule_string", s)
		_ruleRaw, err3 := JsonStringToRuleRaw([]byte(s))
		if err3 != nil {
			slog.Error("JsonStringToRuleRaw_err", "err", err3)
			continue
		}
		//
		_ruleDef, err2 := ast.ConvertRuleRaw2RuleDef(_ruleRaw) // 这个是第一次初始化
		if err2 != nil {
			slog.Error("ConvertRuleRaw2RuleDef", "err", err2)
			continue
		}
		data.RuleList.AddOrUpdate(_ruleDef)
	}
	//
}

func JsonStringToRuleRaw(_data []byte) (*model.RuleRaw, error) {
	_ruleRaw := new(model.RuleRaw)
	err := json.Unmarshal(_data, _ruleRaw)
	if err != nil {
		return nil, errors.New("反序列化规则错误,json_Unmarshal_err:RuleRaw" + err.Error())
	}
	if len(_ruleRaw.Id) < 1 {
		return nil, errors.New("_ruleRaw.Id,缺少ID") // ID是核心 唯一标识
	}
	if len(_ruleRaw.LinkageListRaw) < 2 {
		return nil, errors.New("规则缺少策略")
	}
	// 规则的反控策略,反序列化
	err = json.Unmarshal([]byte(_ruleRaw.LinkageListRaw), &_ruleRaw.LinkageList)
	if err != nil {
		return nil, errors.New("反序列化策略错误,json_unmarshal_err_LinkageList:" + err.Error())
	}
	return _ruleRaw, nil
}

// 过滤数据
func ParseFilterData() {
	for dr := range redisMqData {
		// 挑选数据
		for _, tmpData := range dr.Datas {
			// 平级关系 规则点位 反控点位
			if data.MapPtId.Exist(tmpData.Ptid) {
				_point := data.NewPoint(tmpData.Ptid, dr.Tint, tmpData.Result)
				//spew.Dump("filter_data_point", _point)
				slog.Debug("filter_point", "_p", fmt.Sprintf("%#v", _point))
				// 不确定是否异常, 目前yaoting 测试的部分
				ptIdQueue := data.QueueMap.GetQueue(tmpData.Ptid)
				ptIdQueue.Enqueue(_point)
			}
			// 反控点位, redis 保留最新的一份
			if data.CtrlPtId.Exist(tmpData.Ptid) {
				// redis 的 key
				key_with_pt_id := ctrl_ptid_prefix + tmpData.Ptid
				// redis 写入的数据
				vals := []any{"t", dr.Tint, "v", tmpData.Result}
				go func() {
					intCmd := cache.Rdb0.HSet(context.Background(), key_with_pt_id, vals...)
					if intCmd.Err() != nil {
						slog.Debug("redis_hset_err" + intCmd.Err().Error())
					}
				}()
			}
		}
		// 释放
		dr.Datas = nil
		dr = nil
	}
}

type redisMsgStruct struct {
	Id      string           `json:"id"` // rule_deleted
	MsgType string           `json:"msgtype"`
	Rule    *json.RawMessage `json:"rule"` // rule_changed
}

// 规则更改部分
func ParseRedisMsg() {
	//
	for msg := range redisMqMsg {
		var c redisMsgStruct
		err := json.Unmarshal(bytesconv.StringToBytes(msg), &c)
		if err != nil {
			slog.Error("json.Unmarshal", "err", err)
			continue
		}
		//
		msgType := c.MsgType
		//  {\"rule\":{\"id\":\"0\",\"ruleId\":\"80\",\"status\":\"1\",\"ruleExpression\":\"(${_1000520359} \\u003e 10)\",\"expressionList\":\"${_1000520359} \\u003e 10\",\"ptIdList\":\"_1000520359@10\",\"linkageList\":\"[{\\\"ptId\\\":\\\"1000520359\\\",\\\"setpointOperator\\\":2,\\\"setpointValue\\\":2.0,\\\"triggerInterval\\\":30}]\",\"alarmTime\":\"12\"},\"msgtype\":\"rule_changed\"}"
		if msgType == "points_changed" {
			// 不做处理
			continue
		} else if msgType == rule_changed {
			//
			if c.Rule == nil {
				slog.Error("rule error:c.Rule is nil point")
				continue
			}
			//
			_ruleRaw, err3 := JsonStringToRuleRaw(*c.Rule)
			if err3 != nil {
				slog.Error("JsonStringToRuleRaw_err", "err", err3)
				continue
			}
			//
			_score, _ := strconv.Atoi(_ruleRaw.Id)
			_ruleStr := string(*c.Rule)
			// 这个日志要 严格注意
			slog.Warn(rule_changed, "rule", _ruleStr)
			// redis操作
			go func() {
				// 删除分数 等于id 的数据
				_ = cache.Rdb0.ZRemRangeByScore(ctx, REDIS_KEY_RULE_ENGINE, _ruleRaw.Id, _ruleRaw.Id)
				// 新增数据
				intCmd := cache.Rdb0.ZAdd(ctx, REDIS_KEY_RULE_ENGINE, redis.Z{Score: float64(_score), Member: _ruleStr})
				if err = intCmd.Err(); err != nil {
					slog.Error("redis rdb0 ZAdd", "error", err.Error())
				} else {
					_count, _ := intCmd.Result()
					slog.Warn("redis ZAdd result", "count", _count)
				}
			}()
			// 继续转成规则结构
			// var defaultLogger atomic.Pointer[Logger]
			slog.Info("redis", "rule", spew.Sdump(_ruleRaw))
			// 把原始数据 _ruleRaw 继续解析规则
			_ruleDef, err := ast.ConvertRuleRaw2RuleDef(_ruleRaw) // 这个是redis订阅
			if err != nil {
				slog.Info("ast.ConvertRuleRaw2RuleDef", "error", err)
				continue
			}
			//
			data.RuleList.AddOrUpdate(_ruleDef)
			//
		} else if msgType == rule_deleted {
			// "{\"id\":\"1\",\"msgtype\":\"rule_deleted\"}"
			_id := c.Id
			if len(_id) < 1 {
				slog.Warn("rule_deleted,id长度异常", "node id", _id)
				continue
			}
			// redis操作
			go func() {
				// ZREMRANGEBYSCORE rule_engine 0 0
				intCmd := cache.Rdb0.ZRemRangeByScore(ctx, REDIS_KEY_RULE_ENGINE, _id, _id)
				if err = intCmd.Err(); err != nil {
					slog.Error("redis rdb0 ZRemRangeByScore", "error", err.Error())
				}
			}()
			// redis 删除数据
			slog.Warn(rule_deleted, "node id", _id)
			// 删除规则
			data.RuleList.Remove(_id)
		}
	}
}

// 废弃 乐山的redis 数据反序列化
//func redisDataConvertRuleRaw(_rule map[string]any) (*data.RuleRaw, error) {
//	var _ruleRaw data.RuleRaw
//	_ruleRaw.Id = _rule["id"].(string)
//	_ruleRaw.Status = _rule["status"].(string)
//	_ruleRaw.RuleId = _rule["ruleId"].(string)
//	_ruleRaw.AlarmTime = _rule["alarmTime"].(string)
//	_ruleRaw.PtIdList = _rule["ptIdList"].(string)
//	_ruleRaw.ExpressionList = _rule["expressionList"].(string)
//	_ruleRaw.RuleExpression = _rule["ruleExpression"].(string)
//	_ruleRaw.LinkageListRaw = _rule["linkageList"].(string)
//	//
//	linkageBytes := []byte(_ruleRaw.LinkageListRaw)
//	err := json.Unmarshal(linkageBytes, &_ruleRaw.LinkageList)
//	if err != nil {
//		return nil, err
//	}
//	return &_ruleRaw, nil
//}
